/*
 * Copyright (C) 2008 Matt Falkoski
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.falko.android.raven.animator;

import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

import android.os.SystemClock;

import com.falko.android.raven.renderer.Sprite2D;

public class SpriteExplosion implements Animation.AnimationLogic {

	public final static int MAX_SPRITE_COUNT = 50;
	public final static String SPRITE_COUNT = "SPRITE_COUNT";
	public final static String SPRITE_TEXTURE = "SPRITE_TEXTURE";
	public final static String X_LOC = "X_LOC";
	public final static String Y_LOC = "Y_LOC";
	public final static String WIDTH = "WIDTH";
	public final static String HEIGHT = "HEIGHT";
	public final static String SPRITE_SCALE = "SPRITE_SCALE";
	public final static String MIN_SPRITE_SCALE = "MIN_SPRITE_SCALE";
	public final static String MAX_SPRITE_SCALE = "MAX_SPRITE_SCALE";
	public final static String RAND_SPRITE_SCALE = "RANDOM_SPRITE_SCALE";
	public final static String MODE = "MODE";
	public final static String VELOCITY = "VELOCITY";
	private final static float BASE_SIZE = 12.8f;
	private final static String LAST_TIME = "LAST_TIME";
	private final Random rand = new Random(System.nanoTime());

	public enum GravityMode {
		UP, DOWN, LEFT, RIGHT, NONE, ERROR;

		public static GravityMode fromString(String val) {
			if (UP.toString().equalsIgnoreCase(val)) {
				return UP;
			} else if (DOWN.toString().equalsIgnoreCase(val)) {
				return DOWN;
			} else if (LEFT.toString().equalsIgnoreCase(val)) {
				return LEFT;
			} else if (RIGHT.toString().equalsIgnoreCase(val)) {
				return RIGHT;
			} else if (NONE.toString().equalsIgnoreCase(val)) {
				return NONE;
			} else {
				return ERROR;
			}

		}
	}

	public void onInit(Animation a) {

		Sprite2D sprites[] = a.getSprites();
		float x = a.getFloat(X_LOC);
		float y = a.getFloat(Y_LOC);
		int min = a.getInt(MIN_SPRITE_SCALE);
		int max = a.getInt(MAX_SPRITE_SCALE);
		int velocity = a.getInt(VELOCITY);
		GravityMode mode = GravityMode.fromString(a.getString(MODE));
		rand.setSeed(System.nanoTime());
		for (int i = 0; i < a.getInt(SPRITE_COUNT); ++i) {

			final Sprite2D s = sprites[i];
			int scale;
			if (a.getBool(RAND_SPRITE_SCALE)) {
				scale = rand.nextInt(max - min) + min;
			} else {
				scale = a.getInt(SPRITE_SCALE);
			}

			s.reset();
			s.texture_ = a.getTexture(SPRITE_TEXTURE);
			s.width_ = scale * BASE_SIZE;
			s.height_ = scale * BASE_SIZE;
			s.x_ = x - s.width_ / 2;
			s.y_ = y - s.height_ / 2;

			switch (mode) {
			case UP: {
				s.velocityX_ = rand.nextInt(velocity) - velocity / 2;
				s.velocityY_ = -rand.nextInt(velocity/2);
				break;
			}

			case DOWN: {
				s.velocityX_ = rand.nextInt(velocity) - velocity / 2;
				s.velocityY_ = rand.nextInt(velocity/2);
				break;
			}

			case LEFT: {
				s.velocityX_ = rand.nextInt(velocity / 2);
				s.velocityY_ = rand.nextInt(velocity) - velocity / 2;
				break;
			}

			case RIGHT: {
				s.velocityX_ = -rand.nextInt(velocity / 2);
				s.velocityY_ = rand.nextInt(velocity) - velocity / 2;
				break;
			}

			case NONE: {
				s.velocityX_ = rand.nextInt(velocity) - velocity / 2;
				s.velocityY_ = rand.nextInt(velocity) - velocity / 2;
				if (Math.abs(s.velocityX_) < velocity / 7) {
					s.velocityX_ = s.velocityX_ < 0? -velocity / 7 : velocity / 7;
				}
				if (Math.abs(s.velocityY_) < velocity / 7) {
					s.velocityY_ = s.velocityY_ < 0? -velocity / 7 : velocity / 7;
				}
				break;
			}
			
			default: {
				break;
			}
			}			

			s.visible_ = true;
		}

		a.putLong(LAST_TIME, SystemClock.uptimeMillis());
	}

	public void update(Animation animation) {

		Sprite2D sprites[] = animation.getSprites();
		int width = animation.getInt(WIDTH);
		int height = animation.getInt(HEIGHT);
		int velocity = animation.getInt(VELOCITY);
		float deltaTime = (SystemClock.uptimeMillis() - (long) animation
				.getLong(LAST_TIME)) / 1000f;
		animation.putLong(LAST_TIME, SystemClock.uptimeMillis());
		GravityMode mode = GravityMode.fromString(animation.getString(MODE));

		if (deltaTime > 0.5)
			return; // context was lost so we skip this update

		int count = animation.getInt(SPRITE_COUNT);
		for (int i = 0; i < count; ++i) {
			final Sprite2D s = sprites[i];

			if (!s.visible_)
				continue;

			if (s.y_ > height || s.y_ < -s.height_ 
					|| s.x_ > width  || s.x_ < -s.width_ ) {
				s.visible_ = false;
			} else {
				s.x_ += s.velocityX_ * deltaTime;
				s.y_ += s.velocityY_ * deltaTime;

				switch (mode) {
				case UP: {
					s.velocityX_ += s.velocityX_ == 0 ? 0
							: s.velocityX_ > 0 ? -(velocity / 7) * deltaTime
									: (velocity / 7) * deltaTime;
					s.velocityY_ += (velocity / 3.5) * deltaTime;
					break;
				}

				case DOWN: {
					s.velocityX_ += s.velocityX_ == 0 ? 0
							: s.velocityX_ > 0 ? -(velocity / 7) * deltaTime
									: (velocity / 7) * deltaTime;
					s.velocityY_ -= (velocity / 3.5) * deltaTime;
					break;
				}

				case LEFT: {
					s.velocityY_ += s.velocityX_ == 0 ? 0
							: s.velocityX_ > 0 ? -(velocity / 7) * deltaTime
									: (velocity / 7) * deltaTime;
					s.velocityX_ -= (velocity / 3.5) * deltaTime;
					break;
				}

				case RIGHT: {
					s.velocityY_ += s.velocityX_ == 0 ? 0
							: s.velocityX_ > 0 ? -(velocity / 7) * deltaTime
									: (velocity / 7) * deltaTime;
					s.velocityX_ += (velocity / 3.5) * deltaTime;
					break;
				}

				case NONE:
				default: {
					break;
				}
				
				}
			}
		}
	}

	public boolean visible(Animation animation) {

		Sprite2D sprites[] = animation.getSprites();
		int count = animation.getInt(SPRITE_COUNT);
		for (int i = 0; i < count; ++i) {
			if (sprites[i].visible_)
				return true;
		}
		return false;

	}

	public void render(Animation animation, GL10 gl) {

		Sprite2D sprites[] = animation.getSprites();
		int count = animation.getInt(SPRITE_COUNT);
		for (int i = 0; i < count; ++i) {
			if (sprites[i].visible_) {
				sprites[i].draw(gl);
			}
		}

	}
}
